package com.example.workrecord.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.*;
import com.dingtalk.api.response.*;
import com.dingtalk.oapi.lib.aes.DingTalkJsApiSingnature;
import com.example.workrecord.common.Env;
import com.example.workrecord.entity.AuthInfo;
import com.example.workrecord.entity.CorpUserDetail;
import com.example.workrecord.util.dingtalkopenapi.utils.FileUtils;
import com.example.workrecord.util.dingtalkopenapi.utils.HttpUtil;
import com.example.workrecord.util.dingtalkopenapi.utils.JwtUtils;
import com.example.workrecord.util.dingtalkopenapi.utils.OApiException;
import com.taobao.api.ApiException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;

/**
  *@ClassName: AuthHelper
  *@Description  AccessToken和jsticket的获取封装
  *@Author Mr.Bu
  *@Date 2020/3/4 10:19
  *@Version: 1.0
  */
@Service
public class AuthHelper {

    private Logger logger=LoggerFactory.getLogger(AuthHelper.class);
    @Autowired
    private AuthInfoDaoService service;


    Integer isTrue=0;

    @Value("${dingding.app-key}")
    private String APPKEY;
    @Value("${dingding.agent-id}")
    private String AGENTID;


    /**
     * 调整到1小时50分钟
     */
    public static final long cacheTime = 1000 * 60 * 55 * 2;

    public  String getAccessTokenByCorpId(String corpId) throws OApiException {
        return getAccessToken(corpId,APPKEY);
    }

    /**
     *
     * @param corpId
     * @param appKey
     * @return
     * @throws OApiException
     */
    public  String getAccessToken(String corpId, String appKey) throws OApiException {
        AuthInfo authInfo=service.findByCorpIdAndAppKey(corpId,appKey);
        if(null ==authInfo){
            throw new OApiException("未配置 企业 appkey，请检查！");
        }
        long curTime = System.currentTimeMillis();
        String accToken="";
        if (null==authInfo.getExpires() || curTime - authInfo.getExpires().longValue() >= cacheTime) {
            try {
                logger.info("accToken 过期 ，重新获取...............{}..{}..{} {} {}", corpId, authInfo.getAppKey(), curTime);
                DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
                OapiGettokenRequest request = new OapiGettokenRequest();
                request.setAppkey(authInfo.getAppKey());
                request.setAppsecret(authInfo.getAppSecret());
                request.setHttpMethod("GET");
                OapiGettokenResponse response = client.execute(request);
                if(!response.isSuccess()){
                    throw new OApiException("应用获取token失败，请检查！"+response.getErrmsg());
                }
                accToken=response.getAccessToken();
                authInfo.setAccessToken(accToken);
                authInfo.setExpires(curTime);
                service.update(authInfo.getId(),authInfo);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }else{
            logger.info("accToken 未过期 ，不需要重新获取...............{}..{}..{} {} {}", corpId, authInfo.getAppKey(), curTime, authInfo.getExpires().intValue(), authInfo.getExpires().longValue());
            accToken=authInfo.getAccessToken();
        }
        return accToken;
    }

    /**
     * 获取JSTicket, 用于js的签名计算
     * 正常的情况下，jsapi_ticket的有效期为7200秒，所以开发者需要在某个地方设计一个定时器，定期去更新jsapi_ticket
     */
    public  String getJsapiTicket(String accessToken) throws OApiException {
        JSONObject jsTicketValue = (JSONObject) FileUtils.getValue("jsticket", Env.APP_KEY);
        long curTime = System.currentTimeMillis();
        String jsTicket = "";
        if (jsTicketValue == null || curTime -
                jsTicketValue.getLong("begin_time") >= cacheTime) {
            try {
                DefaultDingTalkClient client=new DefaultDingTalkClient("https://oapi.dingtalk.com/get_jsapi_ticket");
                OapiGetJsapiTicketRequest req=new OapiGetJsapiTicketRequest();
                req.setTopHttpMethod("GET");
                OapiGetJsapiTicketResponse execute=client.execute(req, accessToken);
                if (!execute.isSuccess()) {
                    throw new OApiException("jsapi_ticket获取失败，请检查！");
                }
                jsTicket=execute.getTicket();
                JSONObject jsonTicket=new JSONObject();
                JSONObject jsontemp=new JSONObject();
                jsontemp.clear();
                jsontemp.put("ticket", jsTicket);
                jsontemp.put("begin_time", curTime);
                jsonTicket.put(Env.CORP_ID, jsontemp);
                FileUtils.write2File(jsonTicket, "jsticket");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }else{
            jsTicket=jsTicketValue.getString("ticket");
        }
        return jsTicket;
    }

    public static String sign(String ticket, String nonceStr, long timeStamp, String url) throws OApiException {
        try {
            return DingTalkJsApiSingnature.getJsApiSingnature(url, nonceStr, timeStamp, ticket);
        } catch (Exception ex) {
            throw new OApiException(0, ex.getMessage());
        }
    }

    /**
     * 如果签名数据是通过ajax异步请求的话，签名计算中的url必须是给用户展示页面的url
     * @param url
     * @param corpId
     * @param appKey
     * @return
     */
    public  Map<String,Object> getConfig(String url,String corpId,String appKey) {

        /**
         * 确认url与配置的应用首页地址一致
         */
        System.out.println(url);
        /**
         * 随机字符串
         */
        String nonceStr = "abcdefg";
        long timeStamp = System.currentTimeMillis() / 1000;
        String signedUrl = url;
        String ticket = null;
        String signature = null;
        try {
            String  accessToken = getAccessToken(corpId,appKey);
            ticket = getJsapiTicket(accessToken);
            signature = AuthHelper.sign(ticket, nonceStr, timeStamp, signedUrl);
        } catch (OApiException e) {
            e.printStackTrace();
        }
        Map<String, Object> configValue = new HashMap<>();
        configValue.put("jsticket", ticket);
        configValue.put("signature", signature);
        configValue.put("nonceStr", nonceStr);
        configValue.put("timeStamp", timeStamp);
        configValue.put("corpId",corpId);
        configValue.put("agentId", Env.AGENT_ID);
        return configValue;
    }

    /**
     *
     * @param authInfo
     * @return
     * @throws OApiException
     * @throws ApiException
     */
    public CorpUserDetail login(AuthInfo authInfo) throws OApiException ,ApiException {
        long time=System.currentTimeMillis();
        String  accessToken = getAccessToken(authInfo.getCorpId(),authInfo.getAppKey());
        if(null ==accessToken||accessToken.equals("")){
            throw new OApiException("accessToken获取失败，请检查！");
        }
        String userId=getUserIdInfo(authInfo.getCode(),accessToken);
//        String userId="103612431737659018";
        OapiUserGetResponse userGetResponse=getOapiUserGetResponse(userId,accessToken);
        Set set=new HashSet();
        //应用是公开的，增加鉴权效率，不做应用维度的判断
        if (authInfo.getPub() != null) {
            logger.info("访问公开应用 {} {}", authInfo.getCorpId(), userGetResponse.getUserid());
        } else {
            JSONObject agentIdListByUserId=this.getAgentIdListByUserId( authInfo.getCorpId(), authInfo.getAppKey(),userId,accessToken);
            logger.info("获取用户微应用权限 {} {} {}",  authInfo.getCorpId(),userId, System.currentTimeMillis() - time);
            if (agentIdListByUserId != null && agentIdListByUserId.getInteger("errcode") == 0) {
                JSONArray appList=agentIdListByUserId.getJSONArray("appList");
                for (int i=0; i < appList.size(); i++) {
                    JSONObject obj=appList.getJSONObject(i);
                    Integer agentId=obj.getInteger("agentId");
                    set.add(agentId + "");
                }
            }
        }
        logger.info("用户应用id 列表 {} ", set);
        logger.info("免登时间:{}  ", System.currentTimeMillis() - time);
        CorpUserDetail userDetail=new CorpUserDetail();
        userDetail.setUserid(userGetResponse.getUserid());
        userDetail.setName(userGetResponse.getName());
        userDetail.setMobile(userGetResponse.getMobile());
        userDetail.setCorpId(authInfo.getCorpId());
        userDetail.setPermissionSet(set);
        userDetail.setDepartment(userGetResponse.getDepartment().toString());
        userDetail.setIsTrue(isTrue);
        userDetail.setAvatar(userGetResponse.getAvatar());
        System.out.println(userDetail);
        String sign=JwtUtils.sign(userDetail, 30L * 24L * 3600L * 1000L);
        logger.info("签名token为：{} ", sign);
        userDetail.setToken(sign);
        return userDetail;
    }
    /**
     * 查询微应用权限
     *
     * @return
     */
    public JSONObject getAgentIdListByUserId(String corpId,String appKey,String userId,String accessToken) {
        try {
            String url = "https://oapi.dingtalk.com/microapp/list_by_userid?access_token=" + accessToken + "&userid=" + userId;
            String result = HttpUtil.doGet(url);
            return JSONObject.parseObject(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     *
     * @param code
     * @param accessToken
     * @return
     * @throws ApiException
     */
    public String getUserIdInfo(String code, String accessToken) throws ApiException {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/user/getuserinfo");
        OapiUserGetuserinfoRequest request = new OapiUserGetuserinfoRequest();
        request.setCode(code);
        request.setHttpMethod("GET");
        OapiUserGetuserinfoResponse response=client.execute(request, accessToken);
        if(!response.isSuccess()){
            throw new ApiException("免登失败，请检查！"+response.getErrmsg());
        }
        String userId = response.getUserid();
        return userId;
    }

    /**
     *
     * @param userId
     * @param accessToken
     * @return
     * @throws ApiException
     */
    public OapiUserGetResponse getOapiUserGetResponse(String userId, String accessToken) throws ApiException {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/user/get");
        OapiUserGetRequest request = new OapiUserGetRequest();
        request.setUserid(userId);
        request.setHttpMethod("GET");
        OapiUserGetResponse response = client.execute(request, accessToken);
        if(!response.isSuccess()){
            throw new ApiException("用户详情获取失败，请检查！"+response.getErrmsg());
        }
        return response;
    }

    public static void main(String[] args){
        String roles="418893186,";
        Integer isTrue=0;
        if(roles.contains("1109835711")){
            isTrue=1;
        }
        System.out.println(isTrue);

    }

    /**
     * 获取部门用户列表
     * @param dingId
     * @param accessToken
     */
    public List<String> getOapiUserByDeptId(String dingId, String accessToken) throws ApiException {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/user/getDeptMember");
        OapiUserGetDeptMemberRequest req = new OapiUserGetDeptMemberRequest();
        req.setDeptId(dingId);
        req.setHttpMethod("GET");
        OapiUserGetDeptMemberResponse rsp = client.execute(req, accessToken);
       if(!rsp.isSuccess()){
           throw new ApiException("获取部门用户列表失败"+rsp.getErrmsg());
       }
        return  rsp.getUserIds();
    }

    public CorpUserDetail loginShow(String code) throws Exception {
        AuthInfo authInfo=new AuthInfo();
        authInfo.setCode(code);
        authInfo.setAppKey(APPKEY);
        return login(authInfo);
    }
}
